package com.FrameWork.Synchoronization;

import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.Observable;
import java.util.TreeMap;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.json.JSONArray;
import org.json.JSONObject;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.FrameWork.Common.MyApplication;
import com.FrameWork.Entity.GlobalInfo;
import com.FrameWork.Entity.ProgressEntity;
import com.FrameWork.Utils.DateTimeUtils;
import com.FrameWork.Utils.Utils;
import com.SFA.R;
import com.umeng.analytics.MobclickAgent;

public class Synchronization extends Observable {

	public SynchConfig SynchConfig;
	private Context context;

	// 标记同步是否成功
	public boolean SynchSuccess;

	// / <summary>
	// / 将数据写入流中
	// / </summary>
	// / <param name="strFileName"></param>
	// / <param name="strSQL"></param>
	// / <param name="strUploadTableName"></param>
	// / <returns></returns>
	private int GenerateXMLFile(SQLiteDatabase db, OutputStream writer,
			String strUploadTableName, String key) throws Exception {
		int count = 0;
		if (strUploadTableName != null && strUploadTableName.length() > 0) {
			Cursor dataReader = null;
			try {
				dataReader = db.rawQuery("SELECT * FROM " + strUploadTableName,
						null);

				String promarykey = key;
				// 拼接查询条件
				if (dataReader.moveToNext()) {
					
					writer.write("<t n=\"".getBytes());
					writer.write(strUploadTableName.getBytes());
					writer.write("\">".getBytes());
					writer.write("<k>".getBytes());// 添加主键列名
					writer.write(promarykey.getBytes());
					writer.write("</k>".getBytes());

					do {
						count++;
						writer.write("<r>".getBytes());
						StringBuilder sbRow = new StringBuilder();
						int intCount = dataReader.getColumnCount() - 1;// 最后一列为标志是否上传列，所以不返回
						int i = 0;
						String keyvalue = "";
						while (i < intCount) {

							if (!dataReader.isNull(i)) {
								sbRow.append(dataReader.getString(i).replace(
										'|', ';'));
								if (i == 0)// 获取主键值
									keyvalue = dataReader.getString(dataReader
											.getColumnIndex(promarykey));
							}

							sbRow.append("|");

							i++;
						}
						writer.write(sbRow.toString()
								.substring(0, sbRow.length() - 1)
								.replace("&", "&amp;").replace("<", "&lt;")
								.getBytes());
						writer.write("</r>".getBytes());
						sbRow = null;

						// 更新数据状态为已上传
						updateDirty(db, strUploadTableName, promarykey,
								keyvalue);

					} while (dataReader.moveToNext());
					writer.write("</t>".getBytes());

				}

			} catch (Exception ex) {
				MobclickAgent.reportError(context, ex.getMessage());
				throw new Exception("GenerateXMLFile:" + ex.getMessage());

			} finally {
				if (dataReader != null) {
					dataReader.close();
					
					dataReader = null;
				}
			}
		}
		return count;
	}

	// 修改上传的数据位2，标志上传过，但不可以删除，只有返回成功后或标志为1的才可以删除
	private void updateDirty(SQLiteDatabase db, String tablename, String key,
			String value) {
		db.execSQL(" UPDATE " + tablename + " SET  DIRTY=2 WHERE " + key + "='"
				+ value + "';");
	}

	// /数据上传
	private boolean Upload(ProgressEntity entity) throws Exception {
		int count = 0;
		boolean uploaded = false;
		try {

			TreeMap<Integer, String> hash = MyApplication.getInstance().SyncMonitor.Process.getUploadTablesAndLogic();
			java.io.ByteArrayOutputStream stream = new ByteArrayOutputStream();

			SQLiteDatabase db = MyApplication.getInstance().DataProvider.getWritableDatabase();
			db.beginTransaction();
			for (Integer key : hash.keySet()) {
				String[] values = hash.get(key).split(",");
				count += GenerateXMLFile(db, stream, values[0], values[1]);
			}
			db.setTransactionSuccessful();
			db.endTransaction();
			// 如果存在需要上传的数据
			if (count > 0 && stream.size() > 0) {
				// 上传数据
				String returnValue = PostXMLByWebRequest(stream.toString());
				// 上传完成，需要删除本地数据
				if (returnValue != null && returnValue.length() > 0) {
					entity.Increment += 5;
					entity.Message = "上传数据失败:" + returnValue;
					this.notifyObservers(entity.clone());
					return false;
				} else {
					entity.Increment += 5;
					entity.Message = "上传数据" + count + "条";

					this.notifyObservers(entity.clone());
				}

			}
			uploaded = true;

		} catch (Exception ex) {
			MobclickAgent.reportError(context, ex.getMessage());
			throw new Exception("Aggregation:" + ex.getMessage());
		}
		return uploaded;
	}

	public boolean StartSynchronization(Context context) {
		SynchSuccess = false;
		ProgressEntity entity = new ProgressEntity();
		try {
			entity.Increment = 1;
			entity.Message = "开始同步!";
			this.notifyObservers(entity.clone());
			SynchLogicManager.SynchConfig = SynchConfig;
			// 如果是初始化同步则更新同步逻辑
			if (SynchConfig != null
					&& SynchConfig.getSyncModel() == SyncModel.InitialSync) {
				// 清理数据库
				SynchLogicManager.CleanDataBase();
				// 初始化同步逻辑
				SynchLogicManager.InitLogic(MyApplication.getInstance().SyncMonitor.Process, SynchConfig);
				entity.Increment = 10;
				entity.Message = "数据清理完成!";
				this.notifyObservers(entity.clone());
			}
			if (SynchConfig.getSyncModel() != SyncModel.InitialSync) {
				// 上传数据
				try {
					entity.Increment = 20;
					entity.Message = "开始数据上传";
					this.notifyObservers(entity.clone());
					boolean successful = Upload(entity);
					SynchSuccess = successful;
					if (!SynchSuccess) {
						entity.Increment = 100;
						entity.Message = "同步失败！";
						this.notifyObservers(entity.clone());
						return false;
					}
					entity.Increment += 5;
					entity.Message = "上传数据完成!";
					this.notifyObservers(entity.clone());

					entity.Increment += 5;
					entity.Message = "开始上传图片!";
					this.notifyObservers(entity.clone());
					// 上传照片
					SyncImage();// 单独上传图片
					entity.Increment += 10;
					entity.Message = "上传图片完成!";
					this.notifyObservers(entity.clone());

				} catch (Exception err) {
					entity.Increment = 100;
					entity.Message = err.getMessage();
					this.notifyObservers(entity.clone());
					SynchSuccess = false;
					return SynchSuccess;
				}

			}

			// 下载数据
			if (true) {
				String servicesURL = context.getString(R.string.WebServiceURL);
				try {

					Cursor cursor = SynchLogicManager
							.getDownloadTable(SynchConfig.Version);
					String[] tables = new String[cursor.getCount()];
					int count = 0;

					while (cursor.moveToNext()) {
						tables[count] = cursor.getString(1) + ","
								+ cursor.getString(0);
						count++;
					}
					cursor.close();
					cursor = null;
					System.gc();
					// 添加json参数
					ArrayList<String[]> list = new ArrayList<String[]>();
					list.add(tables);

					HttpClient client = getNewHttpClient();
					HttpPost post = new HttpPost(servicesURL + "download.ashx");
					for (int i = 0; i < list.size(); i++) {
						entity.Increment = 20;
						entity.Message = "开始请求数据!";
						this.notifyObservers(entity.clone());
						String RequestKey = null;
						RequestKey = Utils.GetStringForMD5(GlobalInfo.GetInstance(context).getUserToken()
								+ SynchConfig.Version
								+ context.getResources().getString(R.string.REQUESTKEY));
						// 产生RequestCode
						post.setEntity(new StringEntity(
								setJson(
										GlobalInfo.GetInstance(context).getUserToken(),
										RequestKey, SynchConfig.Version,
										SynchConfig.EnableGzip, list.get(i))
										.toString(), HTTP.UTF_8));
						try {
							// 发送请求并获取反馈
							HttpResponse response = client.execute(post);
							// 判断请求是否成功处理
							if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
								entity.Increment = 30;
								entity.Message = "获取数据成功!";

								this.notifyObservers(entity.clone());

								String jsondata = GZIP.uncompress(response
										.getEntity().getContent());// 数据解压缩
								entity.Increment += 5;
								entity.Message = "开始解析数据!";
								this.notifyObservers(entity.clone());

								if (!SynchLogicManager.ParseData(context,
										jsondata, this, entity))// Parse Data
									// and Update to
									// this local
									// DB.
									return false;
								entity.Increment += 5;
								entity.Message = "解析数据完成!";
								this.notifyObservers(entity.clone());

							} else {
								entity.Increment += 5;
								entity.Message = "Sync Fail!"
										+ response.getStatusLine()
										.getStatusCode();
								this.notifyObservers(entity.clone());
								return false;
							}
						} catch (Exception e) {
							e.printStackTrace();
							entity.Increment += 5;
							entity.Message = "发生错误:" + e.getMessage();
							this.notifyObservers(entity.clone());
							return false;
						}
					}
				} catch (Exception e) {
					entity.Increment += 5;
					entity.Message = "发生错误:" + e.getMessage();
					this.notifyObservers(entity.clone());
					e.printStackTrace();
					return false;
				}
			}

			SynchConfig.setSyncModel(SyncModel.UploadDownload);
			SynchConfig.LastSyncTime = Long.parseLong(DateTimeUtils.GetCurrentTime());
			SynchConfig.Save();
			SynchSuccess = true;

		} catch (Exception err) {
			entity.Increment = 100;
			entity.Message = "发生错误:" + err.getMessage();
			this.notifyObservers(entity.clone());
			return false;
		}

		return true;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.util.Observable#notifyObservers(java.lang.Object)
	 */
	@Override
	public void notifyObservers(Object data) {
		// TODO Auto-generated method stub
		this.setChanged();
		super.notifyObservers(data);
	}

	// 构造函数
	public Synchronization(Context context) {
		this.context = context;

	}

	public Object setJson(String userken, String requestKey,
			String version, boolean gzip, String[] tables) {
		JSONObject obj = new JSONObject();
		try {
			JSONArray arr = new JSONArray();
			int i = 0;
			for (String string : tables) {
				arr.put(i, string);
				i++;
			}

			obj.put("UserToken", userken);
			obj.put("Requestkey", requestKey);
			obj.put("Version", version);
			obj.put("Gzip", gzip);
			obj.put("Tables", arr);
		} catch (Exception e) {
			MobclickAgent.reportError(context, e.getMessage());
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return obj;
	}

	public DefaultHttpClient getNewHttpClient() {
		try {
			KeyStore trustStore = KeyStore.getInstance(KeyStore
					.getDefaultType());
			trustStore.load(null, null);
			SSLSocketFactory sf = new SSLSocketFactory(trustStore);
			sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
			HttpParams params = new BasicHttpParams();
			HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
			HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
			SchemeRegistry registry = new SchemeRegistry();

			if (SynchConfig.UseSSL) {
				registry.register(new Scheme("https", sf,
						SynchConfig.ServerPort));
			} else {
				registry.register(new Scheme("http", PlainSocketFactory
						.getSocketFactory(), SynchConfig.ServerPort));
			}
			ClientConnectionManager ccm = new ThreadSafeClientConnManager(
					params, registry);
			return new DefaultHttpClient(ccm, params);
		} catch (Exception e) {
			return new DefaultHttpClient();
		}
	}

	public void SyncImage() {
		StringBuilder sbURL = new StringBuilder();
		String RequestKey = null;
		RequestKey = Utils.GetStringForMD5(GlobalInfo.GetInstance(context).getUserToken()
				+ SynchConfig.Version
				+ context.getResources().getString(R.string.REQUESTKEY));
		// 产生RequestCode
		sbURL.append( context.getString(R.string.WebServiceURL) + "UploadImage.ashx");
		sbURL.append("?user_code=");
		sbURL.append( GlobalInfo.GetInstance(context).getUserCode());
		sbURL.append("&DOMAINID=");
		sbURL.append( GlobalInfo.GetInstance(context).getDomainID());
		sbURL.append("&version=");
		sbURL.append(SynchConfig.Version);
		sbURL.append("&Gzip=");
		sbURL.append(SynchConfig.EnableGzip ? "1" : "0");
		sbURL.append("&RequestKey=");
		sbURL.append(RequestKey);
		Cursor dataReader  =null;
		try {
			HttpClient client = new Synchronization(null).getNewHttpClient();
			dataReader = MyApplication.getInstance().DataProvider
					.Query(" SELECT * FROM UPLOAD_PHOTO ");
			// 每次上传得数据量
			while (dataReader.moveToNext()) {
				int j = 0;
				String ID="";
				JSONObject obj = new JSONObject();
				while (j <  dataReader.getColumnCount() - 1)
				{
					String ColumnName = dataReader.getColumnName(j);
					
					if(j==0)
						ID= dataReader.getString(j);
					if (ColumnName.equals("PHOTO_BLOB")) {
						byte[] imgbyte = dataReader.getBlob(j);
						obj.put(ColumnName, Base64.encodeToString(imgbyte, true));
					} else {
						obj.put(ColumnName, dataReader.getString(j));
					
					}
					
					j++;
				}
				updateDirty(MyApplication.getInstance().DataProvider.myDataBase,
						"UPLOAD_PHOTO", "ID", ID);
				HttpPost post = new HttpPost(sbURL.toString());
				byte[] ss = null;
				if (SynchConfig.EnableGzip) {
					ss = GZIP.compress(obj.toString());// 压缩json图片数据
				} else
					ss = obj.toString().getBytes();
				post.setEntity(new ByteArrayEntity(ss));
				// 发送请求并获取反馈
				HttpResponse response = client.execute(post);
				post = null;
				ss = null;
				obj = null;
				System.gc();
				// 判断请求是否成功处理
				if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) 
				{

					String result = GZIP.uncompress(response
							.getEntity().getContent());// 数据解压缩
					if (!result.equals("")) 
					{
						// 清楚已上传数据
						JSONArray objarray = new JSONArray(result); 
						for (int ii = 0; ii < objarray.length(); ii++)
						{
							JSONObject object = objarray
									.getJSONObject(ii);
							if (object.getBoolean("success")) 
							{
								MyApplication.getInstance().DataProvider
												.Execute("DELETE FROM  UPLOAD_PHOTO WHERE DIRTY=2"
														+ ";VACUUM UPLOAD_PHOTO;");
							}
						}
						objarray= null;
						
					}
					result = null;
				}
				else
				{
//					String result = null;
//					String resul=result;
				}

			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		finally
		{
			if(dataReader!= null )
			{
				dataReader.close();
				dataReader= null;
			}
		}

	}



	
	// / <summary>
	// / 用WebRequest发送信息到需要SSL验证的页面
	// / </summary>
	// / <param name="ServerTimeStamps"></param>
	// / <param name="DownloadTableNames"></param>
	// / <returns></returns>
	public String PostXMLByWebRequest(String data) throws Exception {
		StringBuilder sbURL = new StringBuilder();
		String RequestKey = Utils.GetStringForMD5( GlobalInfo.GetInstance(context).getUserCode()
				+ Utils.GetStringForMD5( GlobalInfo.GetInstance(context).getUserPassword())
				+ SynchConfig.Version
				+ context.getResources().getString(R.string.REQUESTKEY));
		// 产生RequestCode

		// sbURL.append(SynchConfig.getURL() + "upload.ashx");
		sbURL.append( context.getString(R.string.WebServiceURL) + "upload.ashx");
		sbURL.append("?user_code=");
		sbURL.append(GlobalInfo.GetInstance(context).getUserCode());
		sbURL.append("&pass=");
		sbURL.append(Utils.GetStringForMD5( GlobalInfo.GetInstance(context).getUserPassword()));
		sbURL.append("&version=");
		sbURL.append(SynchConfig.Version);
		sbURL.append("&Gzip=");
		sbURL.append(SynchConfig.EnableGzip ? "1" : "0");
		sbURL.append("&RequestKey=");
		sbURL.append(RequestKey);
		try {
			HttpClient client = new Synchronization(null).getNewHttpClient();
			HttpPost post = new HttpPost(sbURL.toString());
			byte[] bb = null;
			if (SynchConfig.EnableGzip) {
				bb = GZIP.compress(data);
			} else
				bb = data.getBytes();
			post.setEntity(new ByteArrayEntity(bb));

			try {
				// 发送请求并获取反馈
				HttpResponse response = client.execute(post);
				// 判断请求是否成功处理
				if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {

					String result = GZIP.uncompress(response.getEntity()
							.getContent());// 数据解压缩

					if (result.equals("true")) {
						// 清楚已上传数据
						SynchLogicManager.CleanUploadTable();
					} else {
						// 数据上传失败
						return result;
					}

				}
			} catch (Exception e) {
				e.printStackTrace();
				throw e;

			}

		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}

		return "";
	}

}
